﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Sebarf.Services.Interfaces;
using Sebarf.Utils.Interfaces;
using Sebastof.Services.Interfaces;

#endregion

namespace Sebastof.Services.Impl {
	/// <summary>
	/// Description of the class
	/// </summary>
	public class ObjectTreeHelperService : Service, IObjectTreeFlattenerService {
		#region Private Fields

		[ServiceRequest]
		public IObjectHierarchyFlattenerService ObjectHierarchyFlattenerService { get; set; }

		#endregion

		#region IObjectTreeFlattenerService Members

		public IList<IFlattenTreeObjectEntry> GetFlattenTree(object objectToFlatten) {
			var toReturn = new List<IFlattenTreeObjectEntry>();
			var tmpValues = new List<object>();
			if (!(objectToFlatten is IEnumerable || objectToFlatten is ISebastofApplicationObject)) {
				foreach (ExtendMetadata entry in ObjectHierarchyFlattenerService.ExtendedFlatten(objectToFlatten)) {
					toReturn.Add(new StdObjectEntry(entry));
				}
			}
			if (objectToFlatten is Enumerable) {
				foreach (object entry in objectToFlatten as IEnumerable) {
					if (entry is ISebastofApplicationObject) {
						toReturn.Add(new CollecionBasedObjectEntry(entry as ISebastofApplicationObject));
						toReturn.AddRange(GetFlattenTreeForInterlinqObject(tmpValues, (entry as ISebastofApplicationObject)));
					}
					else {
						foreach (ExtendMetadata subEntry in ObjectHierarchyFlattenerService.ExtendedFlatten(objectToFlatten)) {
							toReturn.Add(new StdObjectEntry(subEntry));
						}
					}
				}
			}
			else if (objectToFlatten is ISebastofApplicationObject) {
				toReturn.Add(new CollecionBasedObjectEntry(objectToFlatten as ISebastofApplicationObject));
				toReturn.AddRange(GetFlattenTreeForInterlinqObject(tmpValues, objectToFlatten as ISebastofApplicationObject));
			}
			else {
				foreach (ExtendMetadata entry in ObjectHierarchyFlattenerService.ExtendedFlatten(objectToFlatten)) {
					toReturn.Add(new StdObjectEntry(entry));
				}
			}
			return toReturn;
		}

		#endregion

		private IList<IFlattenTreeObjectEntry> GetFlattenTreeForInterlinqObject(List<object> flattenedValues,
																				 ISebastofApplicationObject objectToFlatten) {
			var toReturn = new List<IFlattenTreeObjectEntry>();
			if (flattenedValues.Contains(objectToFlatten)) {
				return toReturn;
			}
			flattenedValues.Add(this);
			foreach (var entry in objectToFlatten.GetValues()) {
				if (entry.Value is ISebastofApplicationObject) {
					toReturn.Add(new ObjectEntry(objectToFlatten, entry.Key));
					toReturn.AddRange(GetFlattenTreeForInterlinqObject(flattenedValues, entry.Value as ISebastofApplicationObject));
				}
				if (entry.Value is IEnumerable) {
					foreach (object subEntry in entry.Value as IEnumerable) {
						if (subEntry is ISebastofApplicationObject) {
							toReturn.Add(new CollecionBasedObjectEntry(subEntry as ISebastofApplicationObject));
							toReturn.AddRange(GetFlattenTreeForInterlinqObject(flattenedValues, (subEntry as ISebastofApplicationObject)));
						}
					}
				}
			}
			return toReturn;
		}

		#region Private classes

		#region Nested type: CollecionBasedObjectEntry

		public class CollecionBasedObjectEntry : IFlattenTreeObjectEntry {
			private readonly ISebastofApplicationObject m_data;

			public CollecionBasedObjectEntry(ISebastofApplicationObject data) {
				m_data = data;
			}

			#region IFlattenTreeObjectEntry Members

			public object ObjectTreeEntry {
				get { return m_data; }
			}

			public void ReplaceValueOnTreeBy(object newValue) {
			}

			#endregion
		}

		#endregion

		#region Nested type: ObjectEntry

		public class ObjectEntry : IFlattenTreeObjectEntry {
			private readonly ISebastofApplicationObject m_data;
			private readonly string m_key;

			public ObjectEntry(ISebastofApplicationObject obj, string key) {
				m_key = key;
				m_data = obj;
			}

			#region IFlattenTreeObjectEntry Members

			public object ObjectTreeEntry {
				get { return m_data.GetValue(m_key); }
			}

			public void ReplaceValueOnTreeBy(object newValue) {
				m_data.SetValue(m_key, newValue);
			}

			#endregion
		}

		#endregion

		#region Nested type: StdObjectEntry

		public class StdObjectEntry : IFlattenTreeObjectEntry {
			private readonly ExtendMetadata m_data;

			public StdObjectEntry(ExtendMetadata data) {
				m_data = data;
			}

			#region IFlattenTreeObjectEntry Members

			public object ObjectTreeEntry {
				get { return m_data.CurrentObject; }
			}

			public void ReplaceValueOnTreeBy(object newValue) {
				m_data.ParentField.SetValue(m_data.ParentObject, newValue);
			}

			#endregion
		}

		#endregion

		#endregion
	}
}